package client.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JPanel;

import client.network.DrawMailBox;

public class Canvas extends JPanel implements MouseMotionListener,
		MouseListener, Observer {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private static final int MAXIMUM_NBR_POINTS = 60;

	Point oldMouseLocation;
	Point newMouseLocation;

	private DrawMailBox drawMailBox;
	private ArrayList<Point> points;

	private boolean isDrawer = false;

	int lineSize = 5;

	public Canvas(int height, int width, DrawMailBox drawMailBox) {
		setPreferredSize(new Dimension(width, height));
		addMouseMotionListener(this);
		addMouseListener(this);
		this.drawMailBox = drawMailBox;
		drawMailBox.addObserver(this);
		points = new ArrayList<>();
		disableCanvas();

	}

	@Override
	public void paint(Graphics g) {
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, getWidth(), getHeight());
		g.setColor(Color.BLACK);
		g.drawRect(0, 0, this.getWidth() - 1, this.getHeight() - 1);
	}

	private void paintDot(Point p) {
		Graphics2D g = (Graphics2D) getGraphics();
		oldMouseLocation = p;
		g.setStroke(new BasicStroke(lineSize));
		g.drawLine(oldMouseLocation.x, oldMouseLocation.y, oldMouseLocation.x,
				oldMouseLocation.y);
	}

	private void paintLine(Point p) {
		Graphics2D g = (Graphics2D) getGraphics();
		newMouseLocation = p;
		g.setStroke(new BasicStroke(lineSize));
		g.drawLine(oldMouseLocation.x, oldMouseLocation.y, newMouseLocation.x,
				newMouseLocation.y);
		oldMouseLocation = newMouseLocation;
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		if (isDrawer) {
			points.add(e.getPoint());
			if (points.size() == MAXIMUM_NBR_POINTS) {
				sendPoints();
			}
			paintLine(e.getPoint());
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseClicked(MouseEvent e) {

	}

	@Override
	public void mousePressed(MouseEvent e) {
		if (isDrawer) {
			points.add(e.getPoint());
			if (points.size() == MAXIMUM_NBR_POINTS) {
				sendPoints();
			}
			paintDot(e.getPoint());
		}
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		if (isDrawer) {
			sendPoints();
		}
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	private void sendPoints() {
		drawMailBox.addOutgoingPoints(copyPoints(points));
		points.clear();
	}

	@SuppressWarnings("unchecked")
	@Override
	public void update(Observable o, Object arg) {
		if (arg instanceof ArrayList<?>) {
			ArrayList<Point> points = (ArrayList<Point>) arg;
			if (!points.isEmpty()) {
				paintDot(points.get(0));
				for (int i = 1; i < points.size(); i++) {
					paintLine(points.get(i));
				}
			}
		}
	}

	private ArrayList<Point> copyPoints(ArrayList<Point> points) {
		ArrayList<Point> out = new ArrayList<>();
		for (Point p : points) {
			out.add(p);
		}
		return out;
	}

	public void enableCanvas() {
		this.setEnabled(true);
		isDrawer = true;
	}

	public void disableCanvas() {
		this.setEnabled(false);
		isDrawer = false;
	}

	public void clear() {
		Graphics g = getGraphics();
		g.setColor(Color.BLACK);
		g.fillRect(0, 0, getWidth(), getHeight());
		g.setColor(Color.WHITE);
		g.fillRect(1, 1, getWidth() - 2, getHeight() - 2);
		g.setColor(Color.BLACK);
	}

}
